from functools import wraps

from ..error import (RequiredParamMissingException,
    HeaderValueIncorrectException, RequiredHeaderMissingException
)

from flask import abort, request, current_app

def valid_header(header_name, header_value=None, methods=None, fuzzy=True):
    '''
    校验请求头装饰器
    :param header_name: 请求头键
    :param header_value: 请求头值
    :param methods: 要校验的请求方法
    :param fuzzy: 是否模糊匹配请求头值
    :return:
    '''
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            if methods and request.method not in methods:
                return func(*args, **kwargs)
            if not request.headers.has_key(header_name):
                # abort(404, 'Missing Request Header %s'%header_name)
                raise RequiredHeaderMissingException(
                    'Missing Request Header %s'%header_name
                )
            if header_value is None:
                return func(*args, **kwargs)
            if fuzzy:
                if header_value not in request.headers.get(header_name):
                    # abort(404, 'Header Value Incorrect')
                    raise HeaderValueIncorrectException(
                        'Header Value of %s is Incorrect'%header_name
                    )
            else:
                if header_value != request.headers.get(header_name):
                    # abort(404, 'Header Value Incorrect')
                    raise HeaderValueIncorrectException(
                        'Header Value of %s is Incorrect'%header_name
                    )
            return func(*args, **kwargs)
        return wrapper
    return decorator

def param(param_name, required=False, default=None, methods=None):
    '''
    请求参数装配装饰器
    :param param_name: 请求参数名
    :param required: 是否必须
    :param default: 默认参数值
    :param methods: 要校验的请求方法
    :return:
    '''
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            if methods is not None and request.method not in methods:
                return func(*args, **kwargs)
            try:
                if request.method in ('GET', 'DELETE'):
                    param_val = request.args[param_name]
                elif request.method in ('POST', 'PUT'):
                    param_val = request.form[param_name]
            except KeyError:
                if not required:
                    param_val = default
                else:
                    raise RequiredParamMissingException(
                        'required method %s missed' % param_name
                    )
            paramdict = {param_name: param_val}
            return func(*args, **paramdict, **kwargs)
        return wrapper
    return decorator

class RequestBody:
    def __init__(self, param_name, param_type=dict):
        self.param_name, self.param_type = param_name, param_type
    def __call__(self, func):
        self.func = func
        return self.wrapper
    def wrapper(self, *args, **kwargs):
        request_entity = self.param_type(**request.get_json(force=True, silent=True))
        return self.func(*args, **{self.param_name: request_entity}, **kwargs)

# def requestbody(param_name, methods=None, param_type=dict):
#     def decorator(func):
#         def wrapper(*args, **kwargs):
#
#     return decorator
